package com.wangl.generator.wlmybatisgenerator.generator;

import com.google.common.base.CaseFormat;
import com.wangl.generator.wlmybatisgenerator.data.DataStore;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.generator.api.MyBatisGenerator;
import org.mybatis.generator.config.*;
import org.mybatis.generator.internal.DefaultShellCallback;

import java.io.File;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

/**
 * @ClassName StorageService
 * @Description TODO
 * @Author wangl
 * @Date 2021/8/18 17:10
 */
public class GeneratorService {
    private static final GeneratorService INSTANCE = new GeneratorService();

    public static GeneratorService getInstance(){
        return INSTANCE;
    }

    private GeneratorService(){}

    private Context getDefaultContext(){
        Context context = new Context(null);
        context.setId("defaultContext");
        context.addProperty("autoDelimitKeywords","true");
        context.addProperty("beginningDelimiter", "`");
        context.addProperty("endingDelimiter", "`");
        context.addProperty("fileEncoding", "UTF-8");
        context.addProperty("javaFileEncoding", "UTF-8");

        PluginConfiguration serializablePlugin = new PluginConfiguration();
        serializablePlugin.setConfigurationType("org.mybatis.generator.plugins.SerializablePlugin");
        context.addPluginConfiguration(serializablePlugin);

        CommentGeneratorConfiguration commentGeneratorConfiguration = new CommentGeneratorConfiguration();
        commentGeneratorConfiguration.setConfigurationType("org.mybatis.generator.plugins.MyCommentGenerator");
        commentGeneratorConfiguration.addProperty("javaFileEncoding","UTF-8");
        commentGeneratorConfiguration.addProperty("suppressDate","false");
        commentGeneratorConfiguration.addProperty("suppressAllComments","true");
        context.setCommentGeneratorConfiguration(commentGeneratorConfiguration);

        JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = new JavaModelGeneratorConfiguration();
        javaModelGeneratorConfiguration.addProperty("enableSubPackages","true");
        javaModelGeneratorConfiguration.addProperty("trimStrings","true");
        context.setJavaModelGeneratorConfiguration(javaModelGeneratorConfiguration);

        JavaTypeResolverConfiguration javaTypeResolverConfiguration = new JavaTypeResolverConfiguration();
        javaTypeResolverConfiguration.addProperty("forceBigDecimals","true");
        context.setJavaTypeResolverConfiguration(javaTypeResolverConfiguration);

        SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = new SqlMapGeneratorConfiguration();
        context.setSqlMapGeneratorConfiguration(sqlMapGeneratorConfiguration);
        sqlMapGeneratorConfiguration.addProperty("enableSubPackages","true");

        JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = new JavaClientGeneratorConfiguration();
        context.setJavaClientGeneratorConfiguration(javaClientGeneratorConfiguration);
        javaClientGeneratorConfiguration.addProperty("enableSubPackages","true");
        javaClientGeneratorConfiguration.setConfigurationType("XMLMAPPER");

        return context;
    }

    public String generator(MyBatisGeneratorConfig myBatisGeneratorConfig){
        try {
            Context context = getDefaultContext();
            Configuration config = new Configuration();
            config.addContext(context);

            if (myBatisGeneratorConfig.isLombok()){
                PluginConfiguration lombokConfiguration = new PluginConfiguration();
                lombokConfiguration.setConfigurationType("org.mybatis.generator.plugins.LombokPlugin");
                context.addPluginConfiguration(lombokConfiguration);
            }
            if (myBatisGeneratorConfig.isTinyintCastInteger()){
                JavaTypeResolverConfiguration javaTypeResolverConfiguration = context.getJavaTypeResolverConfiguration();
                javaTypeResolverConfiguration.addProperty(PropertyRegistry.TINYINT_CAST_INTEGER, "true");
            }

            JDBCConnectionConfiguration jdbcConnectionConfiguration = new JDBCConnectionConfiguration();
            jdbcConnectionConfiguration.setConnectionURL("jdbc:mysql://" + DataStore.host + ":" + DataStore.port + "/" + myBatisGeneratorConfig.getDatabase() + "?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf-8&autoReconnect=true");
            jdbcConnectionConfiguration.setDriverClass("com.mysql.jdbc.Driver");
            jdbcConnectionConfiguration.setUserId(DataStore.username);
            jdbcConnectionConfiguration.setPassword(DataStore.password);
            context.setJdbcConnectionConfiguration(jdbcConnectionConfiguration);

            String entityPackage = myBatisGeneratorConfig.getEntityPackage();
            String javaPath = myBatisGeneratorConfig.getJavaPath();
            String resourcesPath = myBatisGeneratorConfig.getResourcesPath();

            File dir = new File(javaPath);
            if (!dir.exists()){
                dir.mkdirs();
            }
            JavaModelGeneratorConfiguration javaModelGeneratorConfiguration = context.getJavaModelGeneratorConfiguration();
            javaModelGeneratorConfiguration.setTargetPackage(entityPackage);
            javaModelGeneratorConfiguration.setTargetProject(javaPath);

            String mapperPackage = myBatisGeneratorConfig.getMapperPackage();
            SqlMapGeneratorConfiguration sqlMapGeneratorConfiguration = context.getSqlMapGeneratorConfiguration();
            sqlMapGeneratorConfiguration.setTargetPackage(mapperPackage);
            sqlMapGeneratorConfiguration.setTargetProject(resourcesPath);

            String daoPackage = myBatisGeneratorConfig.getDaoPackage();
            JavaClientGeneratorConfiguration javaClientGeneratorConfiguration = context.getJavaClientGeneratorConfiguration();
            javaClientGeneratorConfiguration.setTargetPackage(daoPackage);
            javaClientGeneratorConfiguration.setTargetProject(javaPath);

            List<String> tableNames = myBatisGeneratorConfig.getTableNames();
            for (String tableName : tableNames) {
                TableConfiguration tableConfiguration = new TableConfiguration(context);
                tableConfiguration.setTableName(tableName);
                tableConfiguration.setDomainObjectName(tableName2Domain(tableName, myBatisGeneratorConfig.getTablePrefix()));
                tableConfiguration.setCountByExampleStatementEnabled(false);
                tableConfiguration.setUpdateByExampleStatementEnabled(false);
                tableConfiguration.setDeleteByExampleStatementEnabled(false);
                tableConfiguration.setSelectByExampleStatementEnabled(false);
                tableConfiguration.setSelectByExampleQueryId("false");
                GeneratedKey generatedKey = new GeneratedKey("id", "Mysql",true, "");
                tableConfiguration.setGeneratedKey(generatedKey);
                context.addTableConfiguration(tableConfiguration);
            }

            DefaultShellCallback callback = new DefaultShellCallback(myBatisGeneratorConfig.isMergeSupport());
            List<String> warnings = new ArrayList<>();
            MyBatisGenerator generator = new MyBatisGenerator(config, callback, warnings);
            Instant start = Instant.now();
            generator.generate(null);
            Instant end = Instant.now();
            System.out.println("生成代码耗时：" + Duration.between(start,end).toMillis());
            for (String warning : warnings) {
                System.err.println(">" + warning);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private String tableName2Domain(String tableName, String tablePrefix){
        if (StringUtils.isNotBlank(tablePrefix) && tableName.startsWith(tablePrefix)){
            tableName = tableName.substring(tablePrefix.length());
        }
        return CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.UPPER_CAMEL, tableName);
    }
}
